#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
服务器监控脚本
监控CPU负载、PHP-FPM进程数、内存使用率
存放路径：/www/wwwroot/bobomonitor
"""

import os
import subprocess
import time
import requests
import json
from datetime import datetime

class ServerMonitor:
    def __init__(self):
        # 告警阈值配置
        self.load_threshold = 2.0           # CPU负载告警阈值
        self.phpfpm_threshold = 60          # PHP-FPM进程数告警阈值
        self.memory_threshold = 85          # 内存使用率告警阈值(%)
        
        # 日志文件路径
        self.log_file = "/www/wwwroot/bobomonitor/server_monitor.log"
        
        # 企业微信机器人webhook（可选，不用可以注释掉）
        self.webhook_url = ""  # 填入你的企业微信机器人webhook地址
        
    def get_load_average(self):
        """获取系统负载"""
        try:
            with open('/proc/loadavg', 'r') as f:
                load = f.read().strip().split()
                return float(load[0])  # 1分钟负载
        except:
            return 0
    
    def get_phpfpm_count(self):
        """获取PHP-FPM进程数"""
        try:
            result = subprocess.run(['ps', 'aux'], capture_output=True, text=True)
            count = len([line for line in result.stdout.split('\n') if 'php-fpm' in line])
            return count
        except:
            return 0
    
    def get_memory_usage(self):
        """获取内存使用率"""
        try:
            with open('/proc/meminfo', 'r') as f:
                lines = f.readlines()
            
            total = int([line for line in lines if line.startswith('MemTotal:')][0].split()[1])
            available = int([line for line in lines if line.startswith('MemAvailable:')][0].split()[1])
            
            used_percent = (total - available) / total * 100
            return round(used_percent, 2)
        except:
            return 0
    
    def send_alert(self, message):
        """发送告警消息"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        alert_msg = f"[{timestamp}] 服务器告警: {message}"
        
        # 确保日志目录存在
        os.makedirs(os.path.dirname(self.log_file), exist_ok=True)
        
        # 写入日志
        with open(self.log_file, 'a', encoding='utf-8') as f:
            f.write(alert_msg + '\n')
        
        # 发送企业微信告警（如果配置了webhook）
        if self.webhook_url:
            try:
                data = {
                    "msgtype": "text",
                    "text": {"content": alert_msg}
                }
                requests.post(self.webhook_url, json=data, timeout=5)
            except:
                pass
        
        print(alert_msg)
    
    def get_top_processes(self):
        """获取CPU占用最高的进程"""
        try:
            result = subprocess.run(['ps', 'aux', '--sort=-%cpu'], capture_output=True, text=True)
            lines = result.stdout.split('\n')[1:6]  # 取前5个进程
            top_processes = []
            for line in lines:
                if line.strip():
                    parts = line.split()
                    if len(parts) >= 11:
                        cpu = parts[2]
                        command = ' '.join(parts[10:])
                        top_processes.append(f"{command[:30]}({cpu}%)")
            return top_processes
        except:
            return []
    
    def check_and_alert(self):
        """检查系统状态并告警"""
        load_avg = self.get_load_average()
        phpfpm_count = self.get_phpfpm_count()
        memory_usage = self.get_memory_usage()
        
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        status_msg = f"[{timestamp}] 负载:{load_avg} PHP-FPM:{phpfmp_count} 内存:{memory_usage}%"
        
        # 确保日志目录存在
        os.makedirs(os.path.dirname(self.log_file), exist_ok=True)
        
        # 正常情况记录到日志
        with open(self.log_file, 'a', encoding='utf-8') as f:
            f.write(status_msg + '\n')
        
        # 检查告警条件
        alerts = []
        
        if load_avg > self.load_threshold:
            top_processes = self.get_top_processes()
            process_info = " | 高CPU进程: " + ", ".join(top_processes[:3]) if top_processes else ""
            alerts.append(f"CPU负载过高: {load_avg}{process_info}")
        
        if phpfpm_count > self.phpfpm_threshold:
            alerts.append(f"PHP-FPM进程过多: {phpfpm_count}")
        
        if memory_usage > self.memory_threshold:
            alerts.append(f"内存使用率过高: {memory_usage}%")
        
        # 发送告警
        if alerts:
            alert_message = f"{status_msg} | " + " | ".join(alerts)
            self.send_alert(alert_message)
        
        return {
            'load': load_avg,
            'phpfpm': phpfpm_count, 
            'memory': memory_usage,
            'alerts': alerts
        }

if __name__ == "__main__":
    monitor = ServerMonitor()
    result = monitor.check_and_alert()
    
    # 如果有告警，退出码为1，方便宝塔识别
    if result['alerts']:
        exit(1)
    else:
        exit(0)
